#include "flash-info.h"
#include "printf.h"
#include "operate-flash.h"
#include "crc-calculate.h"
/*******UART config**********/
#define USART_WRITE_FLASH                          Uart2
#define USART_WRITE_FLASH_ID                       UART_2
#define USART_WRITE_FLASH_TX                       PRINTF_TX
#define USART_WRITE_FLASH_RX                       PRINTF_RX
/*******UART config end**********/

#define WRITE_FLASH_FIFO_TX_SIZE                     128
#define WRITE_FLASH_FIFO_RX_SIZE                     128

#define USART_WRITE_FLASH_BAUDRATE							9600

#define SEND_CNT     (64)

void write_flash_notify(UartNotifyId_t id);

uint8_t write_flash_info[WRITE_FLASH_BUFFER_LENGTH] = {0};

//info current size
static uint8_t write_flash_info_idx = 0;

enum Write_flash_status_e   Write_flash_status = E_WRITE_FLASH_STATUS_IDLE;

uint8_t *write_flash_TxBuffer;
uint8_t *write_flash_RxBuffer;

/*!
 *\brief Init UART
 */
static void uart_init()
{
    write_flash_TxBuffer = (uint8_t *)malloc(WRITE_FLASH_FIFO_TX_SIZE);
    write_flash_RxBuffer = (uint8_t *)malloc(WRITE_FLASH_FIFO_RX_SIZE);
    
    
    UartInit(&USART_WRITE_FLASH, USART_WRITE_FLASH_ID, USART_WRITE_FLASH_TX, USART_WRITE_FLASH_RX);
    UartConfig(&USART_WRITE_FLASH, RX_TX, USART_WRITE_FLASH_BAUDRATE, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL);

    FifoInit(&USART_WRITE_FLASH.FifoTx, write_flash_TxBuffer, WRITE_FLASH_FIFO_TX_SIZE);
    FifoInit(&USART_WRITE_FLASH.FifoRx, write_flash_RxBuffer, WRITE_FLASH_FIFO_RX_SIZE);
}

/*!
 *\brief Init UART, info size, status
 */
static void init_write_flash(void)
{
    uart_init();
    USART_WRITE_FLASH.IrqNotify = write_flash_notify;
    write_flash_info_idx = 0;
    Write_flash_status = E_WRITE_FLASH_STATUS_IDLE;
}

/*!
 *\brief Disable UART, free Buffer
 */
static void deinit_write_flash(void)
{
    USART_WRITE_FLASH.IrqNotify = NULL;
    UartDeInit(&USART_WRITE_FLASH);
    free(write_flash_TxBuffer);
    free(write_flash_RxBuffer);
}

/*!
 *\brief Notify after RX or TX a byte
 */
static void write_flash_notify(UartNotifyId_t id)
{
    if(id == UART_NOTIFY_TX)
    {
        //after receive
    }
    else if(id == UART_NOTIFY_RX)
    {
        uint8_t data;
        if(UartGetChar(&USART_WRITE_FLASH, &data) == 0)
        {
            //receive from raspberry pi
            if(E_WRITE_FLASH_STATUS_IDLE == Write_flash_status && WRITE_FLASH_RASPBERRY_PI_SIGNAL == data)
            {
                Write_flash_status = E_WRITE_FLASH_STATUS_REPLY_OVER;
            }
            //sync info header
            else if(E_WRITE_FLASH_STATUS_REPLY_OVER == Write_flash_status && WRITE_FLASH_INFO_HEADER == data)
            {
                Write_flash_status = E_WRITE_FLASH_STATUS_GET_INFO_HEADER;
            }
            //get info data
            else if(E_WRITE_FLASH_STATUS_GET_INFO_HEADER == Write_flash_status)
            {
                write_flash_info[write_flash_info_idx++] = data;
                if(WRITE_FLASH_DATA_LENGTH == write_flash_info_idx)
                {
                    Write_flash_status = E_WRITE_FLASH_STATUS_RECEIVE_DONE;
                }
            }
        }
    }
}

static bool get_flash_info_crc_status(uint8_t DeV_Eui_length)
{
    if((write_flash_info_idx - 2) != DeV_Eui_length)
    {
        return false;
    }
    uint16_t rx_crc = write_flash_info[write_flash_info_idx-1] | (write_flash_info[write_flash_info_idx-2] << 8);
    uint16_t calc_crc = LoRa_crc_calculate(write_flash_info, write_flash_info_idx - 2);
    if(calc_crc == rx_crc)
    {
        return true;
    }
    return false;
}

/*!
 *\brief Delay to receive a signal from raspberry pi
 */
void Write_read_flash_info(uint8_t DevEui[], uint8_t length)
{
    init_write_flash();
    TimerTime_t delay_origin = RtcGetTimerValue();
    while(RtcGetTimerValue() - delay_origin <= 5000)
    { 
        //send reply signal SEND_CNT times before receive info header
        for(uint8_t i = 0; E_WRITE_FLASH_STATUS_REPLY_OVER == Write_flash_status && i < SEND_CNT; i++)
        {
            UartPutChar(&USART_WRITE_FLASH, (uint8_t) WRITE_FLASH_REPLY_SIGNAL);
            DelayMs(50);
        }
    }
    if(Write_flash_status > E_WRITE_FLASH_STATUS_IDLE)
    {
        delay_origin = RtcGetTimerValue();
        //delay more time
        while(RtcGetTimerValue() - delay_origin <= 5000)
        { 
            
        }
    }
    if(E_WRITE_FLASH_STATUS_RECEIVE_DONE == Write_flash_status)
    {
        bool is_crc_ok = get_flash_info_crc_status(length);
        if(is_crc_ok && true == Write_flash_data(write_flash_info, write_flash_info_idx, E_START_FLASH_ADDR_DEVICE_EUI))
        {
            //send successful signal SEND_CNT times
            for(uint8_t i = 0; i < SEND_CNT; i++)
            {
                UartPutChar(&USART_WRITE_FLASH, (uint8_t) WRITE_FLASH_SUCCESSFUL);
                DelayMs(50);
            }
        }
        delay_origin = RtcGetTimerValue();
        while(RtcGetTimerValue() - delay_origin <= 2000)
        { 
        }
    }
    //disable UART
    deinit_write_flash();
    //read info
    uint8_t *tmp_info = (uint8_t *)malloc(length+2);
    Read_flash_data(tmp_info, length+2, E_START_FLASH_ADDR_DEVICE_EUI);
    uint16_t info_crc = tmp_info[length+1] | (tmp_info[length] << 8);
    if(info_crc != 0 && LoRa_crc_calculate(tmp_info, length) == info_crc)
    {
        memcpy(DevEui, tmp_info, length*sizeof(uint8_t));
    }
    free(tmp_info);
}




